/**
 * This file is part of the CAKIS project.
 * 
 * Copyright (c) 2009-2010 - Florian Arndt, Christian Kerl
 * 
 * @license GNU Lesser General Public License v3 <http://www.opensource.org/licenses/lgpl-3.0.html>
 * @since   10.05.2010
 * @version SVN: $Id: ClientSessionManager.java 120 2010-05-11 20:11:01Z christian-kerl@web.de $
 */
package org.cakis.server.service.session;

import java.util.ArrayList;
import java.util.Date;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.cakis.server.Names;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.log.Log;

/**
 * ClientSessionManager tracks all {@link ClientSession} and {@link ClientSessionRedirectEvent}.
 *
 * @author Christian Kerl
 */
@Name(Names.ClientSessionManager)
@Scope(ScopeType.APPLICATION)
@Startup
public class ClientSessionManager {
    public static final String SessionStorage = Names.ClientSessionManager + ".SessionStorage";
    public static final String EventStorage = Names.ClientSessionManager + ".EventStorage";

    public static final Long Timeout = 300000L; // 5 minutes

    @Logger
    private Log log;

    // in- and outject because there seems to be more than one instance of ClientSessionManager
    @In(value = SessionStorage, required = false)
    @Out(SessionStorage)
    private Set<ClientSessionInfo> sessions;

    // in- and outject because there seems to be more than one instance of ClientSessionManager
    @In(value = EventStorage, required = false)
    @Out(value = EventStorage)
    private LinkedList<ClientSessionRedirectEvent> events;

    public List<ClientSessionInfo> getClientSessions() {
        filterTimedoutSessions();

        return new ArrayList<ClientSessionInfo>(sessions);
    }

    public Deque<ClientSessionRedirectEvent> getEvents() {
        return events;
    }

    @Create
    public void create() {
        sessions = new HashSet<ClientSessionInfo>();
        events = new LinkedList<ClientSessionRedirectEvent>();
    }

    @Observer(ClientSession.EventStarted)
    public void addClientSession(ClientSessionInfo session) {
        log.info("Added #0", session);

        sessions.add(session);
    }

    @Observer(ClientSession.EventUpdated)
    public void updateClientSession(ClientSessionInfo session) {
        if(sessions.contains(session)) {
            sessions.remove(session);
            sessions.add(session);
        }
    }

    @Observer(ClientSession.EventDestroyed)
    public void removeClientSession(ClientSessionInfo session) {
        log.info("Removed #0", session);

        sessions.remove(session);
    }

    @Observer(ClientSession.EventAddEvent)
    public void addClientSessionEvent(ClientSessionRedirectEvent event) {
        events.add(event);
    }

    private void filterTimedoutSessions() {
        Iterator<ClientSessionInfo> it = new ArrayList<ClientSessionInfo>(sessions).iterator();

        Long now = new Date().getTime();

        while(it.hasNext()) {
            ClientSessionInfo session = it.next();

            if((now - session.getLastAccess().getTime()) > Timeout) {
                removeClientSession(session);
            }
        }
    }
}
